//
// Created by 抑~风 on 2022/12/10.
//

#include "../regexp.h"
#include "semantic_analysis.h"

namespace CWJ {
    namespace SEMA_ANALYSIS {

        Scanner::AnnotatedTreePtr TypeResolver::visit(Scanner::AnnotatedTreePtr tree) {
            this->at = tree;
            this->visit(tree->getTree());
            return this->at;
        }

        CWJType* TypeResolver::getType(ResASTNodePtr node){
            if(node->getNodeType() == NodeType::TOKEN){
                const string& val = node->getContext();
                if(val == "INT")    return &CWJType::intType;
                else if(val == "VOID")  return &CWJType::voidType;
                else if(val == "IDENTIFIER")   {

                    auto v = this->at->lookupClass(node,node->getVal());
                    if(v){
//                        cout<<"TypeResolver::getType: "<<node->getVal()<<endl;
                    }
                    return v;
                }
            }
            CWJType* type = nullptr;
            Symbol* sym = nullptr;
            if((sym=this->at->getSymbolOfNode(node)) && sym->getSymbolEnum() == SymbolEnum::TYPE)   return (CWJType*)sym;

            for(auto s : node->getChilds()){
                if((type = this->getType(s)))   return type;
            }
            return nullptr;
        }

        void TypeResolver::getIdent(Scanner::ResASTNodePtr node,string& str){
            if(node->getNodeType() == NodeType::TOKEN){
                const string& val = node->getContext();
                if(val == "IDENTIFIER")   {
                    str = node->getVal();
                    return ;
                }
            }
            for(auto s : node->getChilds()){
                this->getIdent(s,str);
                if(str.size())   return;
            }

            return ;

        }

        void TypeResolver::visit(Scanner::ResASTNodePtr node) {

            if(node->getNodeType() == NodeType::TOKEN){
                return ;
            }

            for(const auto & c : node->getChilds()){
                this->visit(c);
            }
            const auto &ct = node->getContext();
            if(ct == "typeType"){
                auto tt = this->getType(node);
                this->at->addSymbolOfNode(node,tt);
            }
            else if(ct == "typeTypeOrVoid"){
                auto tt = this->getType(node);
                this->at->addSymbolOfNode(node,tt);
            }
            else if(ct == "functionDeclaration"){
                // 函数声明，解决返回值和参数，但是参数在下面的formalParameter可以被解决，// 还没有处理void的情况
                auto tt = this->at->getSymbolOfNode(node->getChilds().front());
                this->at->addSymbolOfNode(node,tt);
            }
            else if(ct == "classDeclaration"){
                // 继承，类
//                auto tt = this->at->lookupClass()
            }
            else if(ct == "variableDeclarators"){
                visitVarDectors(node);
            }
            else if(ct == "formalParameter"){
                // 函数参数
                auto type = this->getType(node);
                string name;
                this->getIdent(node,name);
                this->at->addSymbolOfNode(node,type);
                auto scope = this->at->getScopeOfNode(node);
                // TODO 没有加入函数参数
                Variable* v = nullptr;
                scope->addSymbol(v=new Variable(name,scope,node,type,CwjAny(),false));
                if(scope->getType() == ScopeType::FUNCTION){
                    auto sc = (FunctionScope*)scope;
                    FunctionType* func = sc->getObject();
                    func->addParamType(type);
                    func->addParam(v);
                }
            }

        }

        void TypeResolver::visitVarDectors(ResASTNode *node) {// 变量申明，继承
            auto scope = at->getScopeOfNode(node);
            auto tmp = node;
            auto type = getType(node);
            if(!type) throw runtime_error("TypeResolver::visit : var dec type is nullptr" );
            for(const auto & one : tmp->getChilds()){
                if(one->getVal() == "variableDeclarator"){
                    visitVarDector(scope, type, one);
                }
            }
        }

        void TypeResolver::visitVarDector(Scope *scope, const CWJType *type, ResASTNode::ResASTNodePtr const &one) {
            string name;
            getIdent(one, name);
            Variable* v = nullptr;
            scope->addSymbol(v=new Variable(name,scope,one,(CWJType*)type,CwjAny()));
            at->addSymbolOfNode(one, v);
        }

    }
}

